#include "CircleCollider.h"

using namespace SolidityEngine;

CircleCollider::CircleCollider(float radius, const Vector2D& offset):
    Collider(),
    _radius(radius),
    _offset(offset)
{
    //ctor
}

CircleCollider::~CircleCollider()
{
    //dtor
}

Vector2D CircleCollider::_GetCenter() const
{
    Vector2D centre=_offset;
    Transform2D* transform=_gameobject->GetComponent<Transform2D>();
    if(transform){
        centre=centre+transform->Position();
    }
    return centre;
}

Rect CircleCollider::_GetBounds() const
{
    float diameter=_radius*2.0f;
    Rect rect(-_radius+_offset.X(),-_radius+_offset.Y(),diameter,diameter);
    //do something clever
    return rect;
}

Collision_ptr CircleCollider::_Test(Collider* collider)
{
    //test the type of the collider
    //the colliders must be of the same type to work
    CircleCollider* ccoll = dynamic_cast<CircleCollider*>(collider);
    if(ccoll){
        if(Vector2D::Distance(collider->GetCenter(),this->GetCenter())<(ccoll->Radius()+this->Radius())){
            return Collision_ptr(new Collision(collider->GetGameObject()));
        }
    }
    else{
        CircleCollider* bcoll = dynamic_cast<CircleCollider*>(collider);
        if(bcoll){
            //transform box to be in 'world' coordinates
            Rect current=bcoll->GetBounds();
            current.X()+=bcoll->GetCenter().X();
            current.Y()+=bcoll->GetCenter().Y();

            //get the point list of the box
            Vector2D* points = current.GetPoints();

            float minimum=10000000.0;
            //for each side of the box
            for(int i=0;i<4;i++)
            {
                int j;
                (i==3) ? j=0:j=i+1;
                //get the nearest point for the side
                Vector2D np = Vector2D::NearestPoint(points[i],points[j],ccoll->GetCenter());
                //
                float dist=Vector2D::Distance(np,ccoll->GetCenter());

                if (dist<minimum)
                {
                    minimum=dist;
                }
            }

            if(minimum<_radius)
            {
                 return Collision_ptr(new Collision(collider->GetGameObject()));
            }
        }
    }

    return Collision_ptr();
}

CircleCollider* CircleCollider::_Clone()
{
    return new CircleCollider(*this);
}

